package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/client"
	"github.com/labstack/gommon/log"
	"io"
	//"io/ioutil"
	"time"
)

const (
	DOCKER_API_PORT    = ":6071"
	DOCKER_API_VERSION = "1.27"
	CONFDWATCHAPIURL   = "/kube-apiserver/k8s-api-url"
)

func GetDockerApiUrl(host string) string {
	return "http://" + host + DOCKER_API_PORT
}

func EtcdSet(cli *client.Client, containerId string, key string, value string) error {
	cmd := []string{
		"etcdctl",
		"--endpoints=http://127.0.0.1:2379",
		"--ca-file=/etc/kubernetes/ssl/ca.pem",
		"--cert-file=/etc/kubernetes/ssl/kubernetes.pem",
		"--key-file=/etc/kubernetes/ssl/kubernetes-key.pem",
		"set",
		key,
		value,
	}
	err := DockerExec(cli, containerId, cmd)
	if err != nil {
		return err
	}
	return nil
}

// 获取DockerCient
func GetDockerClient(host string) (*client.Client, error) {
	url := GetDockerApiUrl(host)
	cli, err := client.NewClient(url, DOCKER_API_VERSION, nil, nil)
	if err != nil {
		return nil, err
	}
	return cli, nil
}

func GenerateConfdWatchValue(hosts []string) (apiUrls string) {
	for _, hostIP := range hosts {
		apiUrls += hostIP + ":6443;"
	}
	last := len(apiUrls) - 1
	return apiUrls[0:last]
}

// 执行容器命令 docker exec containerID cmd
func DockerExec(cli *client.Client, containerId string, cmd []string) error {
	execConfig := types.ExecConfig{Cmd: cmd, AttachStderr: false, AttachStdout: false}

	execResp, err := cli.ContainerExecCreate(context.Background(), containerId, execConfig)
	if err != nil {
		return err
	}

	if err := cli.ContainerExecStart(context.Background(), execResp.ID, types.ExecStartCheck{false, false}); err != nil {
		return err
	}

	time.Sleep(10 * time.Second)
	resp, err := cli.ContainerExecInspect(context.Background(), execResp.ID)
	if err != nil {
		return err
	}
	fmt.Println(resp)
	return nil
}

func GenerageWatchCmds(etcdEndPoints string) []string {
	return []string{"confd", "-watch", "-backend", "etcd",
		"-client-ca-keys", "/etc/kubernetes/ssl/ca.pem",
		"-client-cert", "/etc/kubernetes/ssl/kubernetes.pem",
		"-client-key", "/etc/kubernetes/ssl/kubernetes-key.pem",
		"-node", etcdEndPoints, "&"}
}

func FindContianerByName(cli *client.Client, name string) (string, error) {
	args := filters.NewArgs()
	args.Add("name", name)
	listOptions := types.ContainerListOptions{
		All:     true,
		Filters: args,
	}
	containerList, err := cli.ContainerList(context.Background(), listOptions) //对容器名字模糊匹配
	if err != nil {
		return "", err
	}

	name = "/" + name
	if len(containerList) > 0 {
		for _, container := range containerList {
			if container.Names[0] == name { //对容器名字进行精确匹配
				return container.ID, nil
			}
		}
	}
	return "", nil
}

//从容器中复制文件返回字节流
func DockerCpFromContainer(cli *client.Client, containerId string, src string) (io.ReadCloser, error) {
	r, _, err := cli.CopyFromContainer(context.Background(), containerId, src)
	if err != nil {
		return nil, err
	}
	time.Sleep(time.Second * 2)
	return r, nil
}

// 执行kubectl 进行角色绑定
func BindBootstrapRole(hostIP string) error {
	cli, err := GetDockerClient(hostIP)
	if err != nil {
		return err
	}
	//find container
	containerId, err := FindContianerByName(cli, "kube-ctl-cert")
	if err != nil {
		return err
	}
	//cmd
	//cmds := []string{"sh", "/usr/bin/setcontext.sh", hostIP}
	//cmds := []string{"sh", "/usr/bin/setcontext.sh", hostIP}
	//cmds := []string{ "sh", "/usr/bin/approve_csv.sh", hostIP}
	cmds := []string{"cp", "/usr/bin/kubelet"}

	//exec
	if err := DockerExec(cli, containerId, cmds); err != nil {
		return err
	}
	return nil
}

func main() {
	cli, err := GetDockerClient("20.26.38.133")
	if err != nil {
		fmt.Println(err)
	}

	containerId, err := FindContianerByName(cli, "df-master")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(containerId)

	if err = DockerExec(cli, containerId, []string{"ls"}); err != nil {
		log.Error(err)
	}

	//
	//if r, err := DockerCpFromContainer(cli, containerId, "/usr/local/bin/kubelet"); err != nil {
	//	fmt.Println(err)
	//} else {
	//	content, err := ioutil.ReadAll(r)
	//	if err != nil {
	//		fmt.Println(err)
	//	}
	//	certContext := string(content)
	//	fmt.Printf(certContext)
	//}
	//fmt.Println("over")
}
